package com.rk.jarjuggler.action;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataConstants;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.ModifiableModuleModel;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.rk.jarjuggler.gui.LibTypePanel;
import com.rk.jarjuggler.gui.TreeTablePanel;
import com.rk.jarjuggler.model.LibNode;
import com.rk.jarjuggler.service.HttpUtil;

public class AddLibraryDialogAction extends DialogWrapper {

    public static final String JAR_DIR = "lib";
    public static final String SRC_DIR = "srclib";
    public static final String JAVADOC_DIR = "javadoc";

    private LibTypePanel libTypePanel;
    private AnActionEvent anAction;
    private static final String JAR_JUGGLER = "Jar Juggler";

    public AddLibraryDialogAction(Project project, AnActionEvent anAction) {
        super(project, false);
        this.anAction = anAction;
        init();
        setTitle(JAR_JUGGLER);
    }

    protected JComponent createNorthPanel() {
        return new JLabel("Select a library to add to the project:");
    }

    protected JComponent createCenterPanel() {
        TreeTablePanel treeTablePanel = new TreeTablePanel();
        treeTablePanel.setAddAction(new AddAction(treeTablePanel));

        JPanel container = new JPanel(new BorderLayout());
        container.add(treeTablePanel, BorderLayout.CENTER);
        libTypePanel = new LibTypePanel();
        container.add(libTypePanel, BorderLayout.SOUTH);

        return container;
    }

    protected boolean isModuleLibSelected(){
        return libTypePanel.isModuleLibSelected();
    }


    class AddAction implements ActionListener {
        private TreeTablePanel panel;

        public AddAction(TreeTablePanel panel) {
            this.panel = panel;
        }


        public void actionPerformed(ActionEvent actionEvent) {
            java.util.List<LibNode> libNodes = panel.getSelectedPackages();

            Project project = (Project) anAction.getDataContext().getData(DataConstants.PROJECT);
            String projectFolder = getProjectFilePath(project);

            for (LibNode libNode : libNodes) {
                Messages.showInfoMessage(project, "Selected: " + libNode.getJarUrl(), JAR_JUGGLER);
                try {
                    File jarFile = null;
                    File srcFile = null;
                    File javadocFile = null;

                    if (libNode.hasJar()) {
                        jarFile = HttpUtil.downloadFileToProject(libNode.getJarUrl(), projectFolder, JAR_DIR);
                    }
                    if (libNode.hasSrc()) {
                        srcFile = HttpUtil.downloadFileToProject(libNode.getSrcUrl(), projectFolder, SRC_DIR);
                    }
                    if (libNode.hasJavadoc()) {
                        javadocFile = HttpUtil.downloadFileToProject(libNode.getJavadocUrl(), projectFolder, JAVADOC_DIR);
                    }

//                    Messages.showInfoMessage(project, "Finished downloading.  Adding to path", "Jar Juggler");

                    ApplicationManager.getApplication().runWriteAction(new WriteLibrary(isModuleLibSelected(), libNode, project, jarFile, srcFile, javadocFile));

                } catch (Exception e) {
                    e.printStackTrace();
                    Messages.showErrorDialog(project, e.getMessage(), JAR_JUGGLER);
                }
            }
        }

        private String getProjectFilePath(Project theProject) {
            String projectFilePath = theProject.getProjectFilePath();
            String projectFolder = projectFilePath.substring(0, projectFilePath.lastIndexOf(File.separator));
            return projectFolder;
        }
    }

    class WriteLibrary implements Runnable {
        private boolean addAsModuleLib;
        private LibNode libNode;
        private Project project;
        private File jarFile;
        private File srcFile;
        private File javadocFile;


        public WriteLibrary(boolean addAsModuleLib, LibNode libNode, Project theProject, File jarFile, File srcFile, File javadocFile) {
            this.addAsModuleLib = addAsModuleLib;
            this.libNode = libNode;
            this.project = theProject;
            this.jarFile = jarFile;
            this.srcFile = srcFile;
            this.javadocFile = javadocFile;
        }

        public void run() {
            VirtualFileManager virtualFileManager = VirtualFileManager.getInstance();
            virtualFileManager.refresh(false);

            Library.ModifiableModel libraryModel;
            ModifiableRootModel rootModel = null;
            if (addAsModuleLib) {
                // Getting our Module:
                ModifiableModuleModel modifiableModel = ModuleManager.getInstance(project).getModifiableModel();
                Module theModule = modifiableModel.getModules()[0];

                // Getting Module Root Model:
                ModuleRootManager rootManager = ModuleRootManager.getInstance(theModule);
                rootModel = rootManager.getModifiableModel();

                // Creating the new Library, adding its jar:
                Library myLibrary = rootModel.getModuleLibraryTable().createLibrary(getLibName(libNode));
                libraryModel = myLibrary.getModifiableModel();
            } else {
                LibraryTable table = LibraryTablesRegistrar.getInstance().getLibraryTable(project);
                Library myLibrary = table.createLibrary();
                libraryModel = myLibrary.getModifiableModel();
                String libName = getLibName(libNode);
                libraryModel.setName(libName);
            }

            if (libNode.hasJar()) {
                String jarUrl = VirtualFileManager.constructUrl(JarFileSystem.PROTOCOL, HttpUtil.slashify(jarFile.getAbsolutePath()) + JarFileSystem.JAR_SEPARATOR);
                VirtualFile jarVirtualFile = virtualFileManager.findFileByUrl(jarUrl);
                libraryModel.addRoot(jarVirtualFile, OrderRootType.CLASSES);
            }
            if (libNode.hasSrc()) {
                String srcUrl = VirtualFileManager.constructUrl(JarFileSystem.PROTOCOL, HttpUtil.slashify(srcFile.getAbsolutePath()) + JarFileSystem.JAR_SEPARATOR);
                VirtualFile srcVirtualFile = virtualFileManager.findFileByUrl(srcUrl);
                libraryModel.addRoot(srcVirtualFile, OrderRootType.SOURCES);
            }
            if (libNode.hasJavadoc()) {
                String javadocUrl = VirtualFileManager.constructUrl(JarFileSystem.PROTOCOL, HttpUtil.slashify(javadocFile.getAbsolutePath()) + JarFileSystem.JAR_SEPARATOR);
                VirtualFile javadocVirtualFile = virtualFileManager.findFileByUrl(javadocUrl);
                libraryModel.addRoot(javadocVirtualFile, OrderRootType.JAVADOC);
            }

            libraryModel.commit();
            if (addAsModuleLib) {
                rootModel.commit();
            }
        }

        private String getLibName(LibNode libNode) {
            return HttpUtil.getPrefix(HttpUtil.getFileName(libNode.getJarUrl()));

        }
    }
}
